///////////////////////////////////////////////////////////////////////////////////////////////////////////
// Name:	CellSpacePartition.h
//
// Author:	Onyebuchi Ekenta
// 
// Purpose: The purpose of the cell space partition is to optimize collision detection by drastically
//			decreasing the search space for potential collisions. 
//////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef CELL_SPACE_PARTITION_H
#define CELL_SPACE_PARTITION_H

#include "Vector2D.h"
#include <vector>
#include <list>
#include <cassert>
#include "BaseGameEntity.h"
#include "GenericKeys.h"

#include "Globals.hpp"
#include "General Utils.hpp"
#include "GLFT_Font.hpp"

class Pool;

struct Cell
{
  //all the entities inhabiting this cell
  std::list<BaseGameEntity*>    Members;

  //the cell's bounding box 
  GameRectangle BBox;
  list<Pool*> m_Pools;

  Cell(Vector2D topleft,
       Vector2D botright)
  {
	  BBox = GetRect(topleft.x, topleft.y, botright.x, botright.y);

  }
};

class CellSpacePartition
{
private:
	// the required amount of cells in the space
	vector<Cell> m_Cells;

	// this is used to store any valid neighbors when an agent searches its neighboring space
	std::vector<BaseGameEntity*> m_Neighbors;

	// this iterator will be used by the methods next and begin to traverse
	// through the above vector of neighbors
	std::vector<BaseGameEntity*>::iterator m_curNeighbor;

	// the width and height of the world space that the entities inhabit
	double m_dSpaceWidth;
	double m_dSpaceHeight;

	// the number of cells the space is going to divided up into
	int m_iNumCellsX;
	int m_iNumCellsY;

	double m_dCellSizeX;
	double m_dCellSizeY;

	// given a position in the game space this method determines the 
	// relevant cell's index
	 int PositionToIndex(const Vector2D& pos)const;

public:

	CellSpacePartition(double width,
						double height,
						int cellsX,
						int cellsY,
						int MaxEntities);

	 void AddEntity(BaseGameEntity* ent);
	 void UpdateEntity(BaseGameEntity* ent, Vector2D OldPos );

	 void CalculateNeighbors(Vector2D TargetPos, double QueryRadius);

	 void CalculateCollisions(Vector2D TargetPos, double QueryRadius);
	 void CalculateCollisions(BaseGameEntity* anEntity);
	 
	 void CalculateOverlaps(Vector2D TargetPos, double QueryRadius);
	 void CalculateOverlaps(BaseGameEntity* anEntity);

	 BaseGameEntity* begin() {m_curNeighbor = m_Neighbors.begin(); return *m_curNeighbor;}
	 BaseGameEntity* next() {++m_curNeighbor; return *m_curNeighbor;}

	 bool end(){return (m_curNeighbor == m_Neighbors.end()) || (*m_curNeighbor == 0);}
	 
	 void EmptyCells();
	 void RenderCells();

	 void AddPool(Pool* pool); // Adds the given pool to the correct cells
	 bool CollidesWithWater(Vector2D pos, double radius);

};



#endif